type Func<T> = T->T;
type BFunc<T> = T->T->T;
type CNum<T> = Func<Func<T> >;
type INum = CNum<Int>;

var inc:Func<Int> = $x:Int => x + 1;
var i0 = $f:Func<Int> => $x:Int => x;
var isucc: Func<INum>;
isucc = $m:INum => $f:Func<Int> => $x:Int => f(m(f)(x));
var i1:INum;
i1 = isucc(i0);
var i2 = isucc(i1);
var i3 = isucc(i2);
var imul:BFunc<INum>;
imul = $m:INum => $n:INum => $f:Func<Int> => $x : Int => m(n(f))(x);
var i6 = imul(i2)(i3);
println(i6(inc)(0));

type SNum = CNum<String>;
var append:Func<String> = $x:String => x + "a";
var s0 = $f:Func<String> => $x:String => x;
var ssucc: Func<SNum>;
ssucc = $m:SNum => $f:Func<String> => $x:String => f(m(f)(x));
var s1:SNum;
s1 = ssucc(s0);
var s2 = ssucc(s1);
var s3 = ssucc(s2);
var smul:BFunc<SNum>;
smul = $m:SNum => $n:SNum => $f:Func<String> => $x : String => m(n(f))(x);
var s6 = smul(s2)(s3);
println(s6(append)(""));


